<!DOCTYPE html>

<!--
  Google HTML5 slide template

  Authors: Luke Mahé (code)
           Marcin Wichary (code and design)
           
           Dominic Mazzoni (browser compatibility)
           Charles Chen (ChromeVox support)

           Martin Gorner (returnable slides,
		                  graphical intro slide,
		                  next/prev/turn controls,
		                  mobile touch support,
		                  trackpad support,
		                  localization script)

  URL: http://code.google.com/p/html5slides/
-->

<html>
  <head>
    <title>The president is...</title>

    <meta charset='utf-8'>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
    <script type="text/javascript" src='slides.js'></script>
  </head>
  
  <style>
    /* Your individual styles here, or just use inline styles if that’s
       what you want. */
    
    .bookparagraph
	{
		text-align: justify;
		text-indent: 1.5em;
	}
	.footnote
	{
		font-size: 0.5em;
		line-height: 1em;
		color: black;
		font-family: serif;
	}
	.footnote-title
	{
		font-weight: bold;
		color: #94230a;
	}
	
	div.chapter-number
	{
		position: absolute;
		top:0px;
		left:0px;
		padding: 30px;
		padding-left: 25px;
		font-family: cursive;
		font-size: 275%;
		font-weight: 100;
		text-shadow: 3px 3px 5px grey;
		-webkit-transform: translateZ(5px);
		-moz-transform: translateZ(5px);
		-o-transform: translateZ(5px);
		transform: translateZ(5px);
	}
	.g-blue   {color: #446AEA; /* google blue */}
	.g-red    {color: #EE3030;     /* google red */}
	.g-yellow {color: #ffcc00; /* google blue */}
	.g-green  {color: #15A900; /* google green */}
	
	H3.num  {margin-left: 20px;}
	H3.num2 {margin-left: 55px;}
	
    table.table-noborders tr td
    {
    	border: none;
    	padding: 0;
    	margin: 0;
    }
    
    table.table-noborders
    {
    	margin:0;
    }
    
    .pop
    {
    	color: black;
    	font-weight: bold;
    }
    .poplow
    {
    	color: black;
    }
    .popact
    {
    	color: black;
    	font-style: oblique;
    }
    .big
    {
    	font-size: larger;
    	line-height: 1.1em;
    }
    .small
    {
    	font-size: smaller;
    	line-height: 1.1em;
    }
    .x-small
    {
    	font-size: 0.7em;
    	line-height: 1em;
    }
    .jsp
    {
    	color: red !important;
    	font-family: monospace;
    }
    H3.info
    {
    	background-image: url('images/info.png');
    	background-repeat: no-repeat;
    	background-position: 0% 0%;
    	padding-left: 100px;
    	margin-left: -30px;
    	margin-top: -17px;
    	padding-top: 17px;
    	min-height: 80px;
    }
    article.info
    {
    	background-color: #F8FAFF !important;
    }
    .screenshot-left
    {
    	float:left;
    	margin-right:60px;
    	margin-top:10px;
		margin-bottom:10px;
		margin-left:10px;
		padding: 10px;
		border:1px solid #EEEEEE;
		box-shadow: 3px 3px 8px #AAAAAA;
    }
    .screenshot-right
    {
    	float:right;
    	margin-right:10px;
    	margin-top:10px;
		margin-bottom:10px;
		margin-left:60px;
		padding: 10px;
		border:1px solid #EEEEEE;
		box-shadow: 3px 3px 8px #AAAAAA;
    }
    pre.lesspace
    {
    	margin-top: 15px;
    	margin-bottom: 25px;
    }
    .smallcode
    {
    	font-size: 0.54em;
    	line-height: 1.4em;
    }
    .x-smallcode
    {
    	font-size: 0.49em;
    	line-height: 1.3em;
    }
    .u
    {
    	text-decoration: underline;
    }
    .bigserif {font-family: serif; letter-spacing: normal; font-size: 120%;}
    .togglebutton {position: absolute; cursor: pointer}
    .togglebutton img {opacity:0.04; -webkit-transition: 0.3s; -moz-transition: 0.3s; -o-transition: 0.3s;}
    .togglebutton img:hover {opacity:1;}

      .hidden
      {
          opacity:0 !important;
      }
      .rotate-container
      {
          position: absolute;
          width: 80px;
          height: 776px;
          margin-left: -40px;
          margin-top: -388px;
          top: 50%;
          left: 50%;
          -o-transition: 0.3s;
          -moz-transition: 0.3s;
          -webkit-transition: 0.3s;
          -o-transform-style: preserve-3d;
          -moz-transform-style: preserve-3d;
          -webkit-transform-style: preserve-3d;
          cursor: pointer;
      }
      .rotate-button
      {
          position: absolute;
          width: 100%;
          height: 80px;
          opacity: 0.04;
          -o-transition: 0.3s;
          -moz-transition: 0.3s;
          -webkit-transition: 0.3s;
          -o-transform-style: preserve-3d;
          -moz-transform-style: preserve-3d;
          -webkit-transform-style: preserve-3d;
      }
      .rotate-axis
      {
          position: absolute;
          width:100%;
          height: 80px;
          top: 0px;
          left: 0px;
          opacity: 0;
          -webkit-transition: 0.4s;
          -webkit-transition-delay: 0.2s;
          -moz-transition: 0.4s;
          -moz-transition-delay: 0.2s;
          -o-transition: 0.4s;
          -o-transition-delay: 0.2s;
      }
      .rotate-img:hover > .rotate-axis
      {
          opacity:1;
      }
      .rotate-img
      {
          position: absolute;
          top:0px;
          left:0px;
          width: 100%;
          height: 100%;
          -o-transform: rotateX(0deg) rotateZ(0deg);
          -moz-transform: rotateX(0deg) rotateZ(0deg);
          -webkit-transform: rotateX(0deg) rotateZ(0deg);
          -o-transition: 0.3s;
          -moz-transition: 0.3s;
          -webkit-transition: 0.3s;
          -o-transform-style: preserve-3d;
          -moz-transform-style: preserve-3d;
          -webkit-transform-style: preserve-3d;
      }
      .rotate-button:hover
      {
          opacity: 1;
      }
      .rotate-button:hover > .rotate-img
      {
          -o-animation: rotate-360 1s linear infinite;
          -moz-animation: rotate-360 1s linear infinite;
          -webkit-animation: rotate-360 1s linear infinite;
          -o-animation-delay: 0.3s;
          -moz-animation-delay: 0.3s;
          -webkit-animation-delay: 0.3s;
          -o-transform: translateY(-10px) rotateX(-90deg) rotateZ(0deg);
          -moz-transform: translateY(-10px) rotateX(-90deg) rotateZ(0deg);
          -webkit-transform: translateY(-10px) rotateX(-90deg) rotateZ(0deg);
      }
      @-webkit-keyframes rotate-360
      {
          from {-webkit-transform: translateY(-10px) rotateX(-90deg) rotateZ(0deg);}
          to {-webkit-transform: translateY(-10px) rotateX(-90deg) rotateZ(360deg);}
      }
      @-moz-keyframes rotate-360
      {
          from {-moz-transform: translateY(-10px) rotateX(-90deg) rotateZ(0deg);}
          to {-moz-transform: translateY(-10px) rotateX(-90deg) rotateZ(360deg);}
      }
      @-o-keyframes rotate-360
      {
          from {-o-transform: translateY(-10px) rotateX(-90deg) rotateZ(0deg);}
          to {-o-transform: translateY(-10px) rotateX(-90deg) rotateZ(360deg);}
      }
  </style>

  <body style='display: none; '>

    <section class="slides layout-regular template-default" style="-webkit-perspective: 1000px; -moz-perspective: 1000px; -o-perspective: 1000px;">

<!-- 3D toggle button -->
<div class="togglebutton" id="toggle3d-button">
    <img title="3d on/off" src="images/cube2.png" id="togglebutton1" onclick="toggle3D('togglebutton1')"/>
</div>

<!-- 3D turn the slide button -->

<div class="rotate-container" id="rotate-slide-button" onclick="turn3dcurrent()">
    <div class="rotate-button" title="click to turn the slide">
        <div class="rotate-img">
            <img src="images/arrows.svg" style="width:100%; height:100%"/>
            <svg class="rotate-axis" style="-webkit-transform: rotateY(90deg);-moz-transform: rotateY(90deg);-o-transform: rotateY(90deg);">
                <line x1="0" y1="40" x2="80" y2="40" stroke="#a1a1a1" stroke-width="2" stroke-dasharray="12 6 4 6" >
            </svg>
            <svg class="rotate-axis" style="-webkit-transform: rotateY(90deg) rotateX(90deg);-moz-transform: rotateY(90deg) rotateX(90deg);-o-transform: rotateY(90deg) rotateX(90deg);" >
                <line x1="0" y1="40" x2="80" y2="40" stroke="#a1a1a1" stroke-width="2" stroke-dasharray="12 6 4 6" >
            </svg>
        </div>
    </div>
</div>

<!-- next slide button -->
<!-- prev slide button -->
<div class="slide-area" id="next-slide-area" onclick="nextSlide()"></div>
<div class="slide-area" id="prev-slide-area" onclick="prevSlide()"></div>

   
      <!-- Your slides (<article>s) go here. Delete or comment out the
           slides below. -->

<!-- ------------------------------------------------------------------------------- -->
<!-- Introduction, usage -->
        <style>
        article#usage-explanations
        {
        	background: none;
        	border: none;
        	box-shadow: none;
        }
        .summary
        {
            position: absolute;
            font-size: medium;
            top: 3px;
            left: 3px;
            line-height: 1.2em;
            padding: 3px 10px 3px 10px;
            border: 1px grey solid;
            cursor: pointer;
            color: #333333;
        }
        .flag
        {
            width: 30px;
            vertical-align: middle;
        }
        </style>
		<article id="usage-explanations" class="biglogo" onslideenter="hidecontrols()" onslideleave="showcontrols()">
            <div class="summary">
                Available languages: &nbsp;
                 <a onclick="document.location.search='?lang=en';"><img src="template-images/flag-us.png" class="flag"/></a> &nbsp;
                 <a onclick="document.location.search='?lang=fr';"><img src="template-images/flag-fr.png" class="flag"/></a>
            </div>
		<div style="margin-top: 100px; width: 100%; text-align: center">previous<img style="vertical-align: -160px" src="images/keyboard.svg" width="350"/>next&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>
		action
		<br/><br/><br/><br/>action = see the backside of the slide (solutions, additional information, ...)</div>
		
			<translation lang="fr">
                Langues disponibles: &nbsp;
                précédent
                suivant&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
			    action
                action = voir au dos (explications complémentaires, solutions, ...)
			</translation>
		</article>

<!-- ------------------------------------------------------------------------------- -->
<!-- Page de titre -->
	<style>
		
		div#candidats
		{
			position: absolute;
			width: 100%;
			top: 50px;
			left: 50px;
			
			-webkit-transform: translateZ(80px);
			-moz-transform: translateZ(80px);
			-o-transform: translateZ(80px);
			
			/*bug on Firefox: this should not be needed*/
			-moz-backface-visibility: hidden;
		}
		div#candidats img
		{
			margin: 20px;
		}
		div.qmark
		{
			font-size: 7em;
			position: absolute;
			color: rgb(200,200,200);
			
			-webkit-transform:  translateZ(200px);
			-moz-transform:  translateZ(200px);
			-o-transform:  translateZ(200px);
			
			/*bug on Firefox: this should not be needed*/
		   -moz-backface-visibility: hidden;
		}
		div.qmark#q1 { top: 260px; left: 250px; }
		div.qmark#q3 { top: 270px; left: 490px; }
		div.qmark#q2 { top: 280px; left: 730px; }
		.announcement {font-size: 150%; margin: 10px 20px;}
		
	</style>
	<article class="slide3d">
	<!-- on the other side -->
	<div class="backslide3d" style="-webkit-transform-style: preserve-3d">
	  <div id="candidats">
		  <img src="images/candidate1_en.png" />
		  <img src="images/candidate2_en.png" />
		  <img src="images/candidate3_en.png" />
		  <img src="images/candidate4_en.png" />
		  <img src="images/candidate5_en.png" />
		  <img src="images/candidate6_en.png" />
		  <div class="bigserif announcement">Watch this site for election results.</div>
		</div>
		<div class="qmark" id="q1">?</div>
		<div class="qmark" id="q2">?</div>
		<div class="qmark" id="q3">?</div>
	</div>
	
	 
	 <h1 style="padding:0px;margin-top: 130px">
         The president is...<img style="width:300px; vertical-align:-230%; margin-left:40px; margin-right: -30px" src="images/appengine.png" />
	 </h1>
	 <h3 style="margin-top:-110px">
         A codelab in the cloud<br/>with App Engine
	 </h3>
	 <p style="font-size: 0.75em; margin-top: 190px;">
	   Martin Görner, Alexis Moussine-Pouchkine, Didier Girard<br/>
	 </p>
	 
	 <translation lang="fr">
         Résultats annoncés sur ce site.
	    --self--
	    --self--
	    --self--
         Le président est...
         Un exercice de style et de montée
         en charge sur App Engine
	    --self--
	 </translation>
	</article>


<!-- ------------------------------------------------------------------------------- -->
<!-- Projet et prérequis -->

	<article class="slide3d">
	<div class="backslide3d">
	<img src="images/appengine.png" style="width:300px; position:absolute; top:290px; left:310px; -webkit-transform:translateZ(300px); -moz-transform:translateZ(200px); -o-transform:translateZ(200px); /*bug on Firefox: this should not be needed*/-moz-backface-visibility: hidden;"/>
	 
	<p style="margin:30px">
        To help you in this challenge, you can use a powerful tool: App Engine. Our cloud experts will guide you along the way.
	</p>
	 <p style="margin:30px">
         One more thing, you have only 2 hours.
	 </p>
	 
	 <p class="pop" style="font-size: larger; text-align: center; margin-top:410px;">
         Ready to scale ?
	 </p>
	</div>

		<p class="bookparagraph">
            You won the contract of your life. Your job is to build the web site announcing, on D-day, the results of the presidential election.
		</p>
		<p class="bookparagraph">
            The site will have to withstand a peak of potentially <strong>300 million users</strong> on election day. Traffic can peak at above <strong>10 milion simultaneous users</strong> at 8PM when the results are announced. Traffic will then taper off to zero over the next few days. The site must have the social features users expect: comments, satisfaction votes, image publishing, ...
		</p>
		<p class="pop big" style="margin-top: 20px; text-align: center">
            The site cannot fail, <br/>especially not at peak traffic!
		</p>
		
		<translation lang="fr">
            Pour ceci vous disposez d'une plateforme, Google AppEngine et d'experts pour vous guider.
            Le défi est à relever en 2 heures seulement.
            Prêt à relever le défi ?
            Vous venez de gagner un contrat. Il s'agit de développer le site web qui va annoncer au soir des élections le nouveau président de la République Française.
            Le site devra pouvoir accueillir un traffic potentiel maximum de
            50 millions d'utilisateurs
            le jour J. Ce jour là, un pic à
            2 millions d'utilisateurs
            simultanés est attendu a 20h. Ensuite, le lendemain, 1 million d'utilisateurs viendront et les jours suivants quelques milliers d'utilisateurs au grand maximum. Le site devra proposer des fonctions de type social : vote de satisfaction, commentaires, publications d'images, ...
            Il ne doit pas faire défaut, il n'est pas
            concevable qu'il tombe a l'heure H.
		</translation>
	</article>	
	
<!-- ------------------------------------------------------------------------------- -->
<!-- 0. Prérequis et téléchargements -->

    <article class="slide3d" > 
      <div class="backslide3d" style="padding:40px">
         <div class="screenshot-left" style="padding: 0px; text-align: center;margin-top: 20px;"><img src="images/googlemenu.png"/></div>
         <p style="margin-top: 120px">You should now have a "g" icon in the Eclipse toolbar.</p>
         
         
         <div class="footnote" style="clear:left; padding-top: 70px">
         <p style="font-size: 1.1em; font-style: oblique;">Eclipse and Java 7 troubleshooting:</p>
         <table style="margin-top: 10px">
         	<tr>
         		<td><p class="footnote-title">Where is my JDK Java 7 ?</p>
         		<p>On MacOS, run this in a terminal:<br /><code>/usr/libexec/java_home</code></p>
         		<p>On Windows, usually: <br/><code>C:\Program Files\Java\jdk1.7.XXXX</code></p></td>
         		<td colspan="2"><span class="footnote-title">Eclipse starts on JRE 6 and the Google plugin does not like it:</span>
                    force java 7 in <code>eclipse.ini</code> (next to the Eclipse executable, in the app bundle on mac)
	         		
	         		<table class="table-noborders" style="margin-top: 1em">
	         		<tr>
	         			<td style="vertical-align: middle; border-right: grey solid 1px; padding-right: 5px">On MacOS:</td>
	         			<td style="padding-left:5px">
	         			<code>-vm<br/>
         				/Library/Java/JavaVirtualMachines/jdk1.7.XXXX.jdk/Contents/Home</code>
         				</td>
         			</tr>
         			<tr><td>&nbsp;</td></tr>
         			<tr>
         				<td style="vertical-align: middle; border-right: grey solid 1px; padding-right: 5px">On Windows:</td>
         				<td style="padding-left:5px">	
         				<code>-vm<br/>
         				C:\Program Files\Java\jdk1.7.XXXX\bin\javaw.exe</code></td>
         			</tr>
         			
         			</table>
	         		</td>
         	</tr>
         	<tr>
         		<td width="33%"><p class="footnote-title">Which JDK does Eclipse use to compile my projects ?</p>
	         		<code>Eclipse &gt; Preferences &gt; Java &gt; Installed JREs</code></td>
         		<td width="33%"><p class="footnote-title">What Java system libraries does Eclipse use for my project ?</p>
	         		<code>Project &gt; Properties &gt; Java Build Path (Librairies tab)</code></td>
         		<td width="33%"><p class="footnote-title">How to compile in Java 7 ?</p>
	         		<code>Project &gt; Properties &gt; Java Compiler</code></td>
         	</tr>
         </table>
         
      	</div>
      </div>
      
      <img src="images/install-gplugin.png" class="screenshot-right" style="clear:right; padding:0px; margin-top: 00px; margin-right:0px; margin-left:10px" />
      <div class="chapter-number g-blue">0</div>
      <h3 class="num">Setup <span class="small">(Eclipse plugin option, recommended for the codelab)</span></h3>
         <ul style="margin-top:30px">
            <li> <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 7</a> (not JRE)</li>
            <li> <a href="http://eclipse.org/downloads/">Eclipse for Java EE Developers</a></li>
            <li>The libraries <a href="http://repo1.maven.org/maven2/com/googlecode/objectify/objectify/">objectify-4.xx.jar</a> and
                <a href="https://code.google.com/p/guava-libraries/">guava-15.x.jar</a> Download them, explanations later.<br/><br/><br/></li>
            <li><code>Google Plugin for Eclipse</code> <br/> and
            <code>Google App Engine Java SDK</code><br/>
            <span>available in </span> Eclipse: Help › Install New Software › Add ... <code>http://dl.google.com/eclipse/plugin/4.3</code></li>
         </ul>


        <translation lang="fr">
            Vous devriez maintenant avoir une icône "g" dans Eclipse.
            Problèmes avec Eclipse et Java 7 ?
            Où est mon JDK Java 7 ?
            Sur MacOS, lancer ceci dans le terminal:
            --self--
            Sur Windows, habituellement:
            --self--
            Eclipse se lance sur JRE 6 et le plugin Google n'aime pas ça:
            forcer Java 7 dans&nbsp;
            --self--
            (à côté de l'exécutable Eclipse, dans la app bundle sur mac) en ajoutant:
            Sur MacOS:
            --self--
            --self--
            Sur Windows:
            --self--
            --self--
            Quel est le JDK avec lequel Eclipse compile vos projets ?
            Eclipse &gt; Préférences &gt; Java &gt; JREs Installés
            Quelle librairie système Java est utilisée par votre projet ?
            Projet &gt; Propriétés &gt; Java Build Path (onglet Librairies)
            Comment compiler en Java 7 ?
            Projet &gt; Propriétés &gt; Compilateur Java
            --self--
            Prérequis
            (option plugin Eclipse, recommandée pour le codelab)
            --self--
            (pas JRE)
            --self--
            Les librairies&nbsp;
            --self--
            et&nbsp;
            --self--
            à télécharger (explications plus loin)
            --self--
            et&nbsp;
            --self--
            disponible dans
            --self--
            --self--
        </translation>
      </article>

<!-- ------------------------------------------------------------------------------- -->
<!-- 0. Prérequis et téléchargements (MAVEN) -->

	  <article class="slide3d" > 
      <div class="backslide3d" style="padding:40px">
        <div class="small">
            <p>Maven is a project format and build system for Java. Maven projects are portable between IDEs or continuous integration tools (Eclipse, NetBeans, IntelliJ, Jenkins). They include dependencies, including our dependency on the App Engine SDK which will be downloaded automatically.</p>
            <p style="text-align: center; margin-top: 40px"><img style="width:50%" src="images/mavenlogo.gif" /></p>
            <div>
                <p style="margin-top:1em;">Your first "Hello App Engine" servlet:</p>
                <ul>
                    <li>Create a new <span class="pop">Maven Project</span> using an archetype</li>
                    <li>Filter by <code> com.google.appengine.archetypes</code> and select <code> skeleton-archetype (1.7.5)</code>
                    <li>GroupId: <span class="pop">com.myname</span>, ArtefactID: <span class="pop">thepresident</span></li>
                    <li>Create the servlet <code> PresidentServlet.java</code> with<br/><code class="small">response.getWriter().write("Hello App Engine");</code></li>
                    <li>Run local server with the SDK (goal: appengine:devserver)<br />  Eclipse: Run > Run Configurations... > <span class="pop">DevAppServer</span><br/>
                        First run: the App Engine SDK will be downloaded (50MB)
                </ul>
            </div>
        </div>
      </div>
      
      <img src="images/install.png" class="screenshot-right" style="clear:right; padding:0px; margin-top: 00px; margin-right:0px; margin-left:30px" />
      <div class="chapter-number g-blue">0</div>
      <h3 class="num">Setup <span class="small">(Maven option, better for a real project)</span></h3>
         <ul style="margin-top:30px">
            <li> <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 7</a> (not JRE)</li>
            <li> <a href="http://eclipse.org/downloads/">Eclipse for Java EE</a> (or your favourite Java IDE)</li>
            <li> <a href="http://maven.apache.org/download.cgi">Maven</a> (on mac, maven is already installed)<br/><br/></li>
            <li>The<code> m2e-wtp</code> Maven plugin for Eclipse to install from <br/><span> Help › Eclipse Marketplace</span></li>
            <li>Connect to <code> Maven Central</code><br/> Preferences > Maven > Archetypes > Add Remote ... <code>http://repo1.maven.org/maven2</code></li>
         </ul>
         
         <translation lang="fr">
             Maven est un format de projet et un système de build pour Java. Les projets Maven sont portables entre IDEs, outils d'intégration continue etc. (Eclipse, NetBeans, IntelliJ, Jenkins). Ils incluent les dépendances, y compris la dépendance vers le SDK App Engine qui sera téléchargé automatiquement.
             Vore première servlet "Hello App Engine":
             Créer un nouveau
             Projet Maven
             d'après un archetype
             Filtrer par
             --self--
             et sélectionner
             --self--
             --self--
             --self--
             --self--
             --self--
             Créer une servlet
             --self--
             avec
             --self--
             Lancer en local avec le SDK (goal appengine:devserver)
             --self--
             --self--
             Premier run: le SDK App Engine va se télécharger (50MB)
             --self--
             Prérequis
             (option Maven, pour un vrai projet)
             --self--
             (pas JRE)
             --self--
             (ou un autre éditeur Java)
             --self--
             (sur mac, maven est déjà installé)
             Le plugin Maven
             --self--
             pour Eclipse à installer via
             --self--
             Se connecter à
             --self--
             --self--
             --self--
         </translation>
      </article>


<!-- ------------------------------------------------------------------------------- -->
<!-- 1. Ma première servlet "Hello App Engine" -->

<article class="slide3d" >
    <div class="backslide3d" style="padding:40px">
        <img  class="screenshot-left" src="images/project_structure.png" align="left"/>
        Structure of the Web project:
        <p>When you use the assistant to create the servlet, the standard file <code>web.xml</code> is updated to map the servlet.</p>

        <p>
            The file <code>appengine-web.xml</code> contains default values and will be used later to specify the application id as well as other <a href="https://developers.google.com/appengine/docs/java/config/appconfig">App Engine specific parameters</a>.
        </p>

        <p>
        <h3>
            Having trouble ?
        </h3>

        If you see the error <code>"port occupied"</code> when launching your app, use the red "Terminate" button in the <code>"Console"</code> (Window &gt; Show View &gt; Console).
        <img style="vertical-align: top" src="images/stop_server.png"/>
    </div>

    <div class="chapter-number g-red">1</div>
    <h3 class="num">My first servlet "Hello App Engine" <span class="small">(Eclipse plugin option)</span>
    </h3>
    <ul style="margin-top:40px">
        <li>File › New ... › <img style="height:30px; vertical-align:bottom;" src="images/webappproj.png" /></li>
        <li>Name: <span class="pop">ThePresident</span>, package: <span class="pop">com.me.president</span></li>
        <li><form>Uncheck <input type="checkbox" style="vertical-align: middle;" disabled="disabled"/><span class="pop">GWT</span> (for now), Check <input type="checkbox" checked style="vertical-align: middle;" disabled="disabled"/><span class="pop">App Engine</span></form>
            then "Finish" to generate the project.</li>
        <li>Customize your servlet: for example <span class="pop">"Hello App Engine"</span><br/><span>(in</span> src/com/me/president/ThePresidentServlet.java)</li>
        <li><span>Run locally:</span> Run › Run As... › <img style="height:30px; vertical-align:bottom;" src="images/webapp.png" /><br/>
            <span class="small" style="color: red; font-family: monospace;">INFO: The server is running at <a style="color: red;" href="http://localhost:8888/">http://localhost:8888/</a></span></li>
        <li class="small">Then add the <a href="http://repo1.maven.org/maven2/com/googlecode/objectify/objectify">objectify</a> and <a href="https://code.google.com/p/guava-libraries/">guava</a>
            libraries: (1) drag and drop the jar files into war/WEB-INF/lib. (2) Reference them in Project Properties, "Java Build Path", "Libraries" tab.</li>
    </ul>

    <translation lang="fr">
        Structure du projet Web:
        En utilisant l'assistant pour créer la servlet, le fichier standard&nbsp;
        --self--
        est mis à jour pour effectuer le mapping de celle-ci.
        Le fichier&nbsp;
        --self--
        contient des valeurs par défaut et sera utilisé plus tard pour spécifier l'id et la version de l'application et d'autres
        paramètres optionels propres à AppEngine
        --self--
        Un problème?
        Si en relançant vore application vous avez une erreur
        --self--
        , utiliser le bouton rouge "Terminate" dans le haut de la fenêtre
        --self--
        --self--
        --self--
        Ma première servlet "Hello App Engine
        (option plugin Eclipse)
        --self--
        Nom:&nbsp;
        --self--
        --self--
        --self--
        Décocher
        --self--
        (pour aujourd'hui), Cocher
        --self--
        puis "Finish" pour générer le projet.
        Personnaliser la servlet: par exemple
        --self--
        (dans
        --self--
        Lancer en local:
        --self--
        --self--
        --self--
        Puis rajouter les librairies&nbsp;
        --self--
        et&nbsp;
        --self--
        : (1) glisser-déplacer les .jar sur war/WEB-INF/lib. (2) Les référencer dans les propriétés du projet, "Java Build Path", onglet "Libraries", bouton "Add JARs..."
    </translation>
</article>

<!-- ------------------------------------------------------------------------------- -->
<!-- Passons en JSP -->

	  <article class="info slide3d">
	  <div class="empty backslide3d"></div>
        <h3 class="info">
            Let us switch to JSP.<br/>JSP is like HTML, but you can:
        </h3>
        <ul style="margin-top:100px">
          <li>run java code between <span class="pop" style="font-family: monospace;"><span style="color:red"> &lt;%</span>...java code...<span style="color:red">%&gt;</span></span>
          <li>display a value with  <span class="pop" style="font-family: monospace;"><span style="color:red"> &lt;%=</span>foo.getBar()<span style="color:red">%&gt;</span></span>
          <li>access the following JSP objects:<br/><span style="font-family: monospace;"> HttpServletRequest <span class="pop">request</span>, HttpServletResponse <span class="pop">response</span>, JspWriter <span class="pop">out</span></span>
        </ul>
        <p class="small" style="margin-top: 70px;">(Next time, to write cleaner code, prefer GWT or a JavaScript framework like AngularJS)</p>
      
      <translation lang="fr">
          Passons en JSP.
          JSP c'est comme du HTML, mais on peut:
          exécuter du code java entre
          --self--
...code java...
          --self--
          afficher une valeur via
          --self--
truc.getMachin()
          --self--
          avoir accès aux objets JSP suivants:
          --self--
          --self--
          --self--
          --self--
          --self--
          --self--
          (Dans le futur, pour écrire du code propre, préférez GWT ou un framework comme AngularJS)
      </translation>
      </article>
     
<!-- ------------------------------------------------------------------------------- -->
<!-- 2. Votre premier JSP -->
      <style>
      .scrshottext
      {
      	color: black;
      	width: 260px;
      	line-height: 1.15;
      }
      .scrshottext p
      {
      	margin-bottom: 15px;
      }
      .scrshotimg
      {
      	text-align:center;
      	width:100%;
      }
      .scrshotcomment
      {
      	font-size: medium;
      	margin: 0% 5%;
      }
      .scrshotbox
      {
      	height:2.5em;
      	border:1px solid grey;
      	margin: 5px 0px;
      }
      .scrshotlogout
      {
      	 display: inline-block;
      	 text-align: left;
      	 width: 84%;
      }
      .scrshotlogout:hover
      {
      	color: blue;
      	text-decoration: underline;
      }
      </style>
	  <article class="slide3d" > 
      <div class="backslide3d">
<p><span>file:</span> war/comments.jsp</p>
<pre>
&lt;! DOCTYPE html&gt;
&lt;%@ page contentType="text/html;charset=UTF-8" language="java" <span style="color:grey">%&gt;</span>
&lt;html&gt;
  &lt;head&gt;&lt;title&gt;<span>The president is...</span>&lt;/title&gt;&lt;/head&gt;
  &lt;body&gt;
    &lt;H1&gt;<span>The president is...</span>&lt;/H1&gt;
    &lt;img src="<span>obama.png</span>"&gt;
    &lt;p&gt;&lt;%=request.getProtocol() <span style="color:grey">%&gt;</span>&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>This page can be set as the default landing  page in WEB-INF/web.xml</p>
<p>You fill find pictures of the candidates behind the first slide.</p>
      </div>
        <div class="chapter-number g-yellow">2</div>
        <h3 class="num">
            Add a JSP page<br/><br/>
        </h3>
        
        <div style="margin-top:20px;">
        <div class="screenshot-left bigserif scrshottext">
        <p>The president is...</p>
        <div class="scrshotimg"><img src="images/candidate5_en.png"/></div>
        <small><small>HTTP/1.1</small></small>
        </div>
        <p>&nbsp;<br/>&nbsp;<br/>The name of the new president is not known yet so we display something else, for instance:</p>
        <pre>request.getProtocol()</pre>
        </div>
        
       <translation lang="fr">
        fichier:
        --self--
        --self--
Le président est...
Le président est...
hollande.png
		   --self--
           On peut configurer cette page comme page par défaut dans WEB-INF/web.xml
           Vous trouverez les photos des candidats derrière la première diapositive.
           --self--
           Ajouter une page JSP
           Le président est...
           --self--
           On n'a pas encore le nom de l'élu alors faute de mieux on affiche le protocole en utilisant:
           --self--
       </translation>
      </article>

<!-- ------------------------------------------------------------------------------- -->
<!-- 3. Ajouter un formulaire et sa réponse -->

	  <article class="slide3d" > 
      <div class="backslide3d">
<p><span>file:</span> war/comments.jsp</p>
<pre style="margin-bottom:10px" class="smallcode">
&lt;! DOCTYPE html&gt;
&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
&lt;%@ page import="com.google.common.html.HtmlEscapers" %&gt; &lt;!-- Guava --&gt;

&lt;html&gt;
  &lt;body&gt;
    &lt;H1&gt;<span>The president is...</span>&lt;/H1&gt;
    &lt;img src="<span>romney.png</span>" /&gt;
    &lt;% 
        String comment = request.getParameter("user-comment");
        if (comment != null)
	    		comment = HtmlEscapers.htmlEscaper().escape(comment);
    %&gt;
    &lt;p&gt;You: &lt;%=comment %&gt;&lt;/p&gt;
    &lt;form action="" method="post"&gt;
         &lt;textarea name="user-comment" &gt;&lt;/textarea&gt;&lt;br/&gt;
         &lt;input type="submit" value="OK" /&gt;
     &lt;/form&gt; 
  &lt;/body&gt;
&lt;/html&gt;
</pre>
          XSS vulnerability WARNING! DO NOT insert user-generated text into an HTML page without escaping.
      </div>
      
        <div class="chapter-number g-blue">3</div>
        <h3 class="num">
            Add a comments field - without persistency for now
        </h3>
        
        <div style="margin-top:30px;">
        <div class="screenshot-left bigserif scrshottext">
	        <p>The president is...</p>
	        <div class="scrshotimg"><img src="images/candidate2_en.png"/></div>
	        <div class="scrshotcomment"><b>You:</b> not my first choice...
	        <div class="scrshotbox"></div>
	        <form style="text-align: right"><input type="button" value="OK" onclick="noop()"></input></form>
	        </div>
        </div>
        <p>You need an input box:</p>
<pre>
&lt;form action="" method="post"&gt;
   &lt;textarea name="user-comment" &gt;<br/><div style="text-align: right;">&lt;/textarea&gt;
</div>   &lt;input type="submit" value="OK" /&gt;
&lt;/form&gt; 
</pre>
		<p>And a way to get request parameters:</p>
<pre>
request.getParameter("user-comment")
</pre>
        </div>
        
        <translation lang="fr">
            fichier:
            --self--
Le président est...
sarkozy.png
            ATTENTION aux vulnérabilités XSS! Ne jamais insérer dans une page du texte en provenance d'un utilisateur sans escaping.
            --self--
            Ajouter un champ de commentaire - sans persistence pour l'instant
            Le président est...
            Vous:
            pas mon premier choix...
            Il vous faut une zone de saisie:
--self--
            Et la fonction qui donne un paramètre de requête:
        </translation>
      </article>
      
<!-- ------------------------------------------------------------------------------- -->
<!-- 4. Identifier l'utilisateur par son compte Google-->

	  <article class="slide3d" > 
      <div class="backslide3d">
<p>file: war/comments.jsp</p>
<pre class="x-smallcode">
&lt;! DOCTYPE html&gt;
&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
<span class="u">&lt;%@ page import="com.google.appengine.api.users.*" %&gt;</span>
&lt;%@ page import="com.google.common.html.HtmlEscapers" %&gt; &lt;!-- Guava --&gt;

&lt;html&gt;&lt;body&gt;
    &lt;H1&gt;<span>The president is...</span>&lt;/H1&gt; &lt;img src="<span>obama.jpg</span>" /&gt;
&lt;%
    <span class="u">UserService userService = UserServiceFactory.getUserService();</span>
    <span class="u">User user = userService.getCurrentUser();</span>
    <span class="u">if (user == null)</span>
    {%&gt;
        &lt;p&gt;<span>Hello</span>, &lt;a href="&lt;%= <span class="u">userService.createLoginURL(request.getRequestURI())</span> %&gt;"&gt;
        <span>please log in</span>&lt;/a&gt; <span>to post comments</span>.&lt;/p&gt;
    &lt;%}
    else
    {
        String comment = request.getParameter("user-comment");
        if (comment != null)
            comment = HtmlEscapers.htmlEscaper().escape(comment);
%&gt;
        &lt;p&gt;&lt;b&gt;&lt;%=<span class="u">user.getNickname()</span>%&gt;:&lt;/b&gt; &lt;%=comment%&gt;&lt;/p&gt;
    
        &lt;form action="" method="post"&gt;
            &lt;textarea name="user-comment"&gt;&lt;/textarea&gt;&lt;br/&gt;
            &lt;input type="submit" value="OK" /&gt;
            &lt;!-- <span>logout link</span> --&gt;
            &lt;a href="&lt;%= <span class="u">userService.createLogoutURL(request.getRequestURI())</span> %&gt;"&gt;<span>logout</span>&lt;/a&gt;
        &lt;/form&gt;
&lt;% } %&gt;
&lt;/body&gt;&lt;/html&gt;
</pre>
      </div>
      
        <div class="chapter-number g-green">4</div>
        <h3 class="num">
          Identify the user with a Google login
        </h3>
        
        <div style="margin-top:30px;">
        <div class="screenshot-left bigserif scrshottext">
	        <p>The president is...</p>
	        <div class="scrshotimg"><img  src="images/candidate5_en.png"/></div>
	        <div class="scrshotcomment"><b>You:</b> not my first choice...
	        <div class="scrshotbox"></div>
	        <form style="text-align: right"><a class="scrshotlogout">logout</a><input type="button" value="OK" onclick="noop()"></input></form>
	        </div>
        </div>
        
        <p>Use the App Engine <span class="pop">UserService</span> API:</p>
<pre class="smallcode">
UserService userService =
   UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
String n = user.getNickname();
String e = user.getEmail();

</pre>

		<p>You will also need the login and logout URLs:</p>
<pre class="smallcode">
userService.createLoginURL("myTargetURL")
userService.createLogoutURL("myTargetURL");
</pre>
        </div>
        
        <translation lang="fr">
        fichier: war/comments.jsp
        --self--
Le président est...
hollande.png
		--self--
		--self--
		--self--
Bonjour
		--self--
identifiez-vous
pour pouvoir commenter l'élection
		--self--
lien de déconnexion
		--self--
déconnexion
        --self--
        Identifier l'utilisateur par son compte Google
        Le président est...
        Vous:
        pas mon premier choix...
        déconnexion
        Utiliser le 
        UserService
        d'App Engine:
        Il vous fournit aussi les URLs de connexion et déconnexion:
        </translation>
      </article>
 
<!-- ------------------------------------------------------------------------------- -->
<!-- datastore explanation -->

      <article class="info slide3d" >
      <div class="empty backslide3d"></div>
      <h3 class="info">High Replication Datastore<br/>concurrent access, replication, scale</h3>
		<img style="float: left; padding: 10px; margin-right: 25px; margin-top: 15px; background-color: white; border: 1px solid grey" height="420px" src="images/datastore.svg" />        
        <p style="margin-top: 50px;">Data layout: think "XML" rather than "database table"</p>
        <p>Indexed queries only.</p>
        <p>Eventually consistent queries.</p>
        <p class="poplow">Entity = kind + id + <br/>(multivalued) properties</p>
        
        <translation lang="fr">
        High Replication Datastore
        réplication, accès simultanés, montée en charge
        Organisation des données: penser "XML" plutôt que tables.
        Requêtes indexées uniquement.
        Cohérence à terme des requêtes.
        --self--
        --self--
        </translation>
      </article>
      
<!-- ------------------------------------------------------------------------------- -->
<!-- 5. Conserver les commentaires sur le serveur. -->

	  <article class="slide3d" > 
      <div class="backslide3d">
<p><span>file:</span> src/com/me/president/Comments.java</p>
<pre class="x-smallcode lesspace" style="margin-bottom: 15px;">
package <span>com.me.president</span>;
import java.util.*;
import com.google.appengine.api.datastore.*;
import com.google.appengine.api.datastore.Entity;

public class Comments {
    static public void store(String text, String user) {
        Entity commentEntity = new Entity("Comment");
        commentEntity.setProperty("user", user);
        commentEntity.setProperty("date", new Date());
        commentEntity.setProperty("text", text);

        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        datastore.put(commentEntity);
    }
	
    static public List&lt;Entity&gt; retrieveAll() {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        Query query = new Query("Comment");
        query.addSort("date", Query.SortDirection.DESCENDING);
        return datastore.prepare(query).asList(FetchOptions.Builder.withLimit(100));
    }
}
</pre>
Usage: 
<pre class="x-smallcode lesspace" style="display:inline-block; margin-top:0px; vertical-align: top;">
// store:
Comments.store("Hello", "Nicolas");
// retrieve:
List&lt;Entity&gt; comments = Comments.retrieveAll();
for (Entity commentEntity: comments) { ... commentEntity.getProperty("text") ... }
</pre>
      </div>
      
        <div class="chapter-number g-red">5</div>
        <h3 class="num">
          Store comments on the server
        </h3>
        
        <div style="margin-top:30px;">
        <div class="screenshot-left bigserif scrshottext">
	        <p>The president is...</p>
	        <div class="scrshotimg"><img  src="images/candidate2_en.png"/></div>
	        <div class="scrshotcomment"><b>You:</b>: he will have to do.
	        <div class="scrshotbox"></div>
	        <b>George:</b> I voted for him.<br/>
	        <b>Bar:</b> so unfair!
	        <form style="text-align: right"><a class="scrshotlogout">logout</a><input type="button" value="OK" onclick="noop()"></input></form>
	        </div>
        </div>
        
        <p>Low level datastore access:</p>
<pre class="smallcode lesspace">
DatastoreService datastore =
 DatastoreServiceFactory.getDatastoreService();
</pre>
        <p>Write:</p>
<pre class="smallcode lesspace">
Entity commentEntity = new Entity("Comment");
commentEntity.setProperty("date", new Date());
commentEntity.setProperty("text", text);
datastore.put(commentEntity);
</pre>
        <p>Read: <span class="small">100 results sorted by date</span></p>
<pre class="x-smallcode lesspace">
Query query = new Query("Comment");
query.addSort("date", Query.SortDirection.DESCENDING);
List&lt;Entity&gt; results =
   datastore.prepare(query)
      .asList(FetchOptions.Builder.withLimit(100));
</pre>
        </div>
        
        <translation lang="fr">
        fichier:
        --self--
--self--
Utilisation:
        --self--
        Conserver les commentaires sur le serveur
        Le président est...
        Vous
        Ah! ça ira, ça ira, ça ira
        Nicolas:
        j'ai voté pour lui.
        François:
        c'est injuste.
        déconnexion
        Accès bas niveau au datastore:
        &Eacute;criture:
        Lecture:
        100 résultats triés par date
        </translation>
      </article>

<!-- ------------------------------------------------------------------------------- -->
<!-- 6. Conserver les commentaires sur le serveur avec Objectify -->

<article class="slide3d" >
    <div class="backslide3d">
        <p><span>file:</span> src/com/me/president/ObjectifyDAO.java</p>
<pre class="x-smallcode lesspace">
package com.me.president;
import com.googlecode.objectify.Objectify;     import com.googlecode.objectify.ObjectifyService;

public class ObjectifyDAO
{
    static { ObjectifyService.register(Comment.class); } <span>// register all @Entity classes</span>
    static Objectify ofy() { return ObjectifyService.ofy(); }  <span>// proxy for Objectify</span>
}
</pre>
        <p><span>file:</span> src/com/me/president/Comment.java</p>
<pre class="x-smallcode lesspace">
package com.me.president;
import java.util.Date; import java.util.List;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Index;
import static com.me.president.ObjectifyDAO.ofy; <span>// now ofy() goes through the DAO</span>

@Entity public class Comment
{
   @Id Long id;     @Index Date date;     public String user, text;

   public Comment() {}
   public Comment(String text, String user) { this.user = user; this.text = text; this.date = new Date(); }

   public static void store(String text, String user) { ofy().save().entity(new Comment(text, user)); }

   public static List&lt;Comment&gt; retrieveAll()
   { return ofy().load().type(Comment.class).order("-date").limit(100).list(); }
}
</pre>

    </div>

    <div class="chapter-number g-blue">6</div>
    <h3 class="num">
        The same thing with Objectify 4
    </h3>

    <div style="margin-top:20px;">
        <div class="screenshot-left" style="margin-right: 45px; width:258px">
            Use a Plain Old Java Object (POJO):
<pre class="smallcode lesspace">
@Entity
public class Comment
{
    @Id Long id;
    @Index Date date;
    String user;
    String text;

    public Comment() {}
    ...
}
</pre>
            <p class="small">If the Id is of type Long, it will be generated automatically on write.</p>
        </div>
        <p>Registering data classes in a Data Access Object:</p>
<pre class="x-smallcode lesspace">
public class ObjectifyDAO
{<span>// register all @Entity classes</span>
 static { ObjectifyService.register(Comment.class); }
<span>// proxy for Objectify</span>
 static Objectify ofy() {return ObjectifyService.ofy();}
}
<span>// then use ofy() thanks to the declaration:</span>
import static com.me.president.ObjectifyDAO.ofy;
</pre>
        <p>Write:</p>
<pre class="smallcode lesspace">
ofy().save().entity(new Comment(text, user));
</pre>
        <p>Read: <span class="small">100 results sorted by date</span></p>
<pre class="x-smallcode lesspace">
List&lt;Comment&gt; list = ofy().load().type(Comment.class)
                   .order("-date").limit(100).list();
for (Comment c: list) { ... }
</pre>
    </div>
    
    <div class="small" style="margin-left: 200px; margin-right:200px; text-align: center">
    Objecify 4 also requires the <a href="https://code.google.com/p/objectify-appengine/wiki/Setup">ObjectifyFilter in web.xml</a>.
    </div>

    <translation lang="fr">
        fichier:
        --self--
// enregistrement des classes @Entity
// proxy pour Objectify
        fichier:
        --self--
// ofy() passe désormais par le DAO
        --self--
        La même chose avec Objectify 4
        Utiliser un Plain Old Java Object (POJO):
        L'écriture en base auto-génère l'id si il est de type Long.
        Enregistrement des classes et Data Access Object:
// enregistrer toutes les classes @Entity
// proxy pour Objectify
// puis utiliser ofy() grâce à la déclaration:
        &Eacute;criture:
        Lecture: 
        100 résultats triés par date
        Il faut aussi mettre en place
        ObjectifyFilter dans web.xml
        --self--
    </translation>
</article>

<!-- ------------------------------------------------------------------------------- -->
<!-- architecture explanation -->
<style>
	.archimage
	{
		
		width:276px;
		display:inline-block;
		vertical-align: top;
		text-align: center;
	}
	.archtext
	{
		display:inline-block;
		width:180px;
		text-align: right;
		color: black;
		font-style: italic;
	}
	.newarchimage
	{
		width: 300px;
		/*border:1px grey solid;
		background-color: white*/
	}
</style>
    <article class="info slide3d" >
    <div class="empty backslide3d"></div>
      <h3 class="info">App Engine application architecture</h3>
      
		<div class="archimage">
			<div style="border:#b4a464 inset 8px;background-color: #f1e9db;">"SYSTEM 2000"<br/><img src="images/oldarch.png" width="250px"/>
			    <div class="x-small" style="padding: 5px; ">
			         session state in RAM<br/>
			         with sticky load balancing
			     </div>
			 </div>
			 <div class="small" style="text-align: left; margin-top: 5px">
			     <span class="pop">☠</span> pb on instance failure<br/>
			     <span class="pop">☠</span> insufficient memory<br/>
			     <span class="pop">☠</span> slow load balancing<br/>
			     <span class="pop">☠</span> database scalability pb<br/>
			     
			</div>
			</div>
		<div class="archtext small">
		    <div style="margin-top:47px;">datastore→</div>
		    <div  style="margin-top:30px;">memcache→</div>
		    <div  style="margin-top:80px;">frontends→</div>
		    <div  style="margin-top:80px;">efficient load balancing→</div>
		</div>
		<div class="archimage newarchimage">Google App Engine<br/><img src="images/newarch.png" width="300px"/>
		<div class="x-small" style="padding: 5px; ">stateless instances, state stored in memcache and datastore</div>
		</div>
        
        <translation lang="fr">
         Architecture d'application sur App Engine
         “système 2000”
         session en RAM avec
         sticky load balancer
         --self--
         pb sur arrêt d'instance
         --self--
         mémoire insuffisante
         --self--
         load balancing lent
         --self--
         pb scalabilité base
         --self--
         --self--
         --self--
         load balancing efficace→
         --self--
         instances stateless, état dans memcache et datastore
        </translation>
      </article>
      
<!-- ------------------------------------------------------------------------------- -->  
<!-- 6. Garder les commentaires en memcache -->
      
      <article class="slide3d">
      <div class="backslide3d">
          <p><span>file:</span> /src/com/me/president/Comment.java</p>
          <p class="small" >The Comment class must be Serializable</p>
<pre class="lesspace smallcode">
public class Comment <span class="u">implements Serializable</span>
</pre>
          <p class="small" style="margin:0">Create a new method for retrieving comments with caching:</p>
<pre class="lesspace smallcode">
public static List&lt;Comment&gt; retrieveAllCached() {
    MemcacheService cache = MemcacheServiceFactory.getMemcacheService();
    List&lt;Comment&gt; comments = (ArrayList&lt;Comment&gt;)cache.get("100Comments");
    if (comments == null) {
        <span>// read from Datastore</span>
        comments = retrieveAll();
        <span>// write to Memcache</span>
        cache.put("100Comments", new ArrayList&lt;Comment&gt;(comments));
    }
    return comments;
}
</pre>
          <p class="small" style="margin:0">Finally, invalidate the cache on each new comment:</p>
<pre class="lesspace smallcode">
import static com.me.president.ObjectifyDAO.ofy;

public static void store(String text, String user) {
	ofy().save().entity(new Comment(text, user));
	<span class="u">MemcacheServiceFactory.getMemcacheService().delete("100Comments")</span>; // flush cache
}
</pre>
      </div>
      
            <div class="chapter-number g-yellow">7</div>
      		<h3 class="num">Optimize comments with Memcache</h3>
      		<div style="margin-top:70px;">
				<div class="screenshot-left" style="margin-right: 45px; width:258px">
				<p class="small">The interface:</p>
<pre class="smallcode lesspace">
MemcacheService cache =
   MemcacheServiceFactory 
     .getMemcacheService();
     
cache.put("myKey", Object);
cache.get("myKey");
cache.delete("myKey");
</pre>
				<p class="small">Memcache makes sure all your instances see the same value.</p>
		        </div>
			    <p style="text-align: justify;">Just keep the result of the last request in Memcache (serialized) until a new comment is added.</p>

          <p>
            Memcache offers fast access and less contention for data primarily fetched from the datastore.
          </p>

		
          </div>
          
          <translation lang="fr">
          fichier:
          --self--
          La classe Comment doit devenir sérialisable:
          --self--
          On crée une nouvelle méthode pour la lecture des commentaires (avec cache):
// lecture à partir du Datastore
// enregistrement dans Memcache  
          Enfin, on invalide le cache à chaque nouveau commentaire:
          --self--
          --self--
          Optimiser les commentaires avec Memcache
          L'interface:
          Memcache s'assure que toutes vos instances voient la même valeur.
          Il suffit de garder le résultat de la dernière requête en Memcache (sérialisée) tant qu'un nouveau commentaire n'a pas été écrit.
          L'utilisation de Memcache permet un accès rapide, avec moins de risques de contention, à des données issues principalement du datastore.
          </translation>
      </article>

<!-- ------------------------------------------------------------------------------- -->      
<!-- 10. deploy to App Engine -->

      <article class="slide3d" > 
      <div class="backslide3d">
      
<p>file: war/WEB-INF/appengine-web.xml</p>
<pre class="smallcode lesspace">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;appengine-web-app xmlns=&quot;http://appengine.google.com/ns/1.0&quot;&gt;
    &lt;!-- <span>Your application id as defined on</span> http://appengine.google.com --&gt;
    &lt;application&gt;<span>thepresident-is</span>&lt;/application&gt;
    &lt;!-- <span>The version of your application, it can be a string (alpha, beta, ...)</span> --&gt;
    &lt;version&gt;1&lt;/version&gt;
    ...
&lt;/appengine-web-app&gt;
</pre>
<p>Reference documentation on&nbsp;<a href="https://developers.google.com/appengine/docs/java/config/appconfig">appengine-web.xml</a>.</p>
<p class="small">This configuration is also possible via the Eclipse plugin:</p>
<p><img src="images/appengine-nameapp.png"/></p>

      </div>
        <div class="chapter-number g-red">8</div>
        <h3 class="num">
          Deploy to App Engine
        </h3>
        <p>&nbsp;</p>
        <ul>
         <li>Go to <a href="http://appengine.google.com">http://appengine.google.com</a> and create an application id. Your app will be accessible at the URL <code>http://myappid.appspot.com</code></li>
         <li>Add the app id to <code>appengine-web.xml</code></li>
         <li>Deploy (App Engine plugin for Eclipse): choose "Deploy to App Engine..." in the  "g" menu.</li>
        </ul>
          <p>&nbsp;</p>
          <p>&nbsp;</p>
        <div class="small">(maven option: maven goal <span class="pop">appengine:update</span><br/>Eclipse (Maven): Run > Run Cofigurations... > <span class="pop">UpdateApplication)</div>
        
        <translation lang="fr">
        fichier: war/WEB-INF/appengine-web.xml
Votre ApplicationId sur
lepresident-est
Version de votre application, cela peut etre un texte (alpha, beta, etc...)
        Documentation de référence sur 
appengine-web.xml
 .
        Le plugin App Engine pour Eclipse a aussi un réglage de projet pour l'App id : 
        --self--
        Déployer sur App Engine!
        Aller sur 
        --self--
        et créer un identifiant pour votre application. Elle sera accessible à l'adresse 
        http://monidentifiant.appspot.com
        Spécifier cet identifiant dans 
        appengine-web.xml
        Déployer (plugin Eclipse): choisir "Deploy to App Engine..." dans le menu "g".
        (option maven: maven goal 
        appengine:update
        --self--
        --self--
        </translation>
      </article>
      
<!-- ------------------------------------------------------------------------------- -->
<!-- keep building ? -->
	
	<article class="fill slide3d">
		<div class="backslide3d" style="padding:60px;color: black;">
		
		<h3 style="padding-left:45px">On the following slides:</h3>
		<ol start="9" style="list-style-image: none;" class="small">
        <li>CRON jobs</li>
        <li>Sharded counters</li>
        <li>Composite datastore indices</li>
		<li>Uploading images with Blobstore and ImageService</li>
		<li>Securing admin URLs</li>
		<li>Receiving emails</li>
		</ol>
		
		<table><tr><td style="border:none">
			<p style="font-weight: 600; color:rgb(51, 51, 51); margin-left:-20px">More on App Engine:</p>
			<ul>
			<li><a href="http://developers.google.com/appengine/docs/java/taskqueue/">Task queues</a>
			and <a href="http://developers.google.com/appengine/docs/java/backends/">Backends</a>
			</li>
			<li><a href="http://developers.google.com/appengine/docs/java/search/overview">Full Text Search</a></li>
			<li><a href="http://developers.google.com/cloud-sql/">Google Cloud SQL</a></li>
			<li><a href="https://developers.google.com/storage/">Google Cloud Storage</a></li>
			</ul>
		</td><td style="border:none; padding-left:30px">
			<p style="font-weight: 600; color:rgb(51, 51, 51); margin-left:-20px">And beyond:</p>
			<ul>
			<li><a href="http://developers.google.com/bigquery/">Google BigQuery</a></li>
			<li><a href="http://developers.google.com/prediction/">Google Prediction API</a></li>
			<li><a href="http://developers.google.com/compute/">Google Compute Engine</a></li>
			</ul>
		</td></table>
		
		</div>
		<img src="images/spacestation.jpg" />
		
		<H1 style="background-color: white;
		           opacity:1;
		           padding: 40px 20px;
		           background-image: url('images/appengine_small.png');
		           background-repeat: no-repeat;
		           background-position: 95% 50%;
		           border-radius: 10px;
		           ">Keep building ?
		</H1>
		
		
		<translation lang="fr">
		Il vous reste à découvrir:
            Les tâches planifiées CRON
            Les compteurs éclatés
            Les indices composites dans le datastore
		L'upload d'une image avec Blobstore et ImageService
		Comment protéger les URLs administrateur
		Comment recevoir des emails
		Pour vous perfectionner:
		--self--
		et&nbsp;
		--self--
		--self--
		--self--
		--self--
		Et au-delà d'AppEngine:
		--self--
		--self--
		--self--
		On continue ?
		</translation>
	</article>

<!-- ------------------------------------------------------------------------------- -->
<!-- 7. Cron pour afficher le président élu -->

<article class="slide3d">
    <div class="backslide3d">
        <p class="small">The cron servlet writes the name of the elected president into the datastore.<br/><span>file:</span> /src/com/me/president/CronServlet.java</p>
      <pre class="x-smallcode lesspace">
public class CronServlet extends HttpServlet
{   @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
    {
        Entity Elected = new Entity("Elected");
        Elected.setProperty("name", "<span>Barack obama</span>"); //<span>or Mitt Romney</span>
        DatastoreServiceFactory.getDatastoreService().put(Elected);
    }
}</pre>
        <p class="small">Servlet mapping in WEB-INF/web.xml, with access restrictions:</p>
      <pre class="x-smallcode lesspace">
&lt;servlet&gt;
   &lt;servlet-name&gt;CronServlet&lt;/servlet-name&gt; &lt;servlet-class&gt;com.me.thepresident.CronServlet&lt;/servlet-class&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
   &lt;servlet-name&gt;CronServlet&lt;/servlet-name&gt; &lt;url-pattern&gt;/cronAllowPresidentDisplay&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt
&lt;security-constraint&gt;
  &lt;web-resource-collection&gt;   &lt;url-pattern&gt;/cron*&lt;/url-pattern&gt;   &lt;/web-resource-collection&gt;
  &lt;auth-constraint&gt;           &lt;role-name&gt;admin&lt;/role-name&gt;        &lt;/auth-constraint&gt;
&lt;/security-constraint&gt;</pre>
        <p class="small">Conditional display (file war/comments.jsp):</p>
      <pre class="x-smallcode lesspace" style="margin-bottom: 0px">
Entity e = DatastoreServiceFactory.getDatastoreService().prepare(new Query("Elected")).asSingleEntity();
if (e == null) /*<span>wait message</span>*/ else /*<span>display president</span>*/ e.getProperty("name");</pre>
    </div>

    <div class="chapter-number g-yellow">9</div>
    <h3 class="num">Display the name of the president at 08:00pm sharp using a Cron job</h3>

    <div style="margin-top:20px;">
        <div class="screenshot-left bigserif scrshottext" style="margin-right: 40px; margin-top: 40px">
            <p>The president is:</p>
            <div class="scrshotimg"><img src="images/candidate5_en.png"/></div>
            <div style="text-align: center"><small>Barack Obama</small></div>
        </div>

        <p>Cron jobs are servlets. Their URL is defined in web.xml.</p>
        <p style="margin-bottom: 20px;">
            Their periodicity can be set in WEB-INF/cron.xml (<a href="https://developers.google.com/appengine/docs/java/config/cron">full syntax</a>):</p>

	        <pre class="smallcode">
&lt;?xml version="1.0" ?&gt;
&lt;cronentries&gt;
  &lt;cron&gt;
    &lt;url&gt;/cronAllowPresidentDisplay&lt;/url&gt;
    &lt;schedule&gt;6 of May 20:00&lt;/schedule&gt;
&lt;!-- every 2 mins, every sunday 9:00 --&gt;
    &lt;timezone&gt;Europe/Paris&lt;/timezone&gt;
  &lt;/cron&gt;
&lt;/cronentries&gt;</pre>

        <translation lang="fr">
            La servlet: elle écrit le nom du président élu dans le datastore
            fichier:
            --self--
            François Hollande
            ou un autre
            Son mapping dans WEB-INF/web.xml, avec restriction d'accès:
            Affichage conditionnel (fichier war/comments.jsp)
message d'attente
affichage du président
            --self--
            Afficher le nom du président à 20h00 précises avec une tâche planifiée Cron
            Le président est...
            François Hollande
            Les Cron lancent des servlets dont l'URL est définie dans web.xml.
            Périodicité à configurer dans WEB-INF/cron.xml (
            syntaxe complète
            ) :
        </translation>
</article>

<!-- ------------------------------------------------------------------------------- -->
<!-- info slide Sharded Counters -->

<article class="slide3d info">
    <div class="empty backslide3d"></div>
    <h3 class="info">What is a sharded counter ?</h3>
    <p class="small" style="font-size: 80%; margin-top: -10px">Writes to the same datastore entity are limited to a few<br/>writes per second: so how can I implement a counter ?
        <br/>⇒Atomic increment in Memcache and a sharded counter in Datastore.</p>
    <p style="text-align: center;"><img src="images/shardedcounter.svg" width="100%"/></p>

    <translation lang="fr">
        Qu'est-ce qu'un compteur éclaté ?
        Les écritures sur la même entité du datastore sont limitées
        à quelques-unes par seconde: comment faire un compteur ?
        ⇒Incrément atomique dans Memcache et compteur éclaté dans Datastore.
    </translation>
</article>

<!-- ------------------------------------------------------------------------------- -->
<!-- 9. Implémenter un compteur éclaté -->

<style>
    .counter
    {
        display: inline-block;
        width: 40px;
        height: 40px;
        background-color: #0076CC;
        border-radius: 4px;
        border: 1px solid #4486DD;
        color:white;
        font-weight: bold;
        text-align: center;
    }
    td.countercell
    {
        padding:0px;
        text-align: center;
        border: none;
        font-size: large;
        font-weight: normal;
        line-height: 36px;
    }
    #shardedcounterslide pre
    { margin-bottom: 0px; }
    #shardedcounterslide p
    { margin-top: 15px; }

</style>
<article id="shardedcounterslide" class="slide3d">
    <div class="backslide3d">
      <pre class="lesspace smallcode" style="float:left; width:400px; height:610px; margin-right: 20px; font-size: 0.5em">
import static com.me.president.ObjectifyDAO.ofy;

@Entity
public class Counter {
  @Id String key;
  @Index String name;
  @Index Long value;

  Counter() {}  // Empty constructor
  Counter(String name, Integer shard_N, Long val) {
    this.name = name;
    this.value = val;
    key = name + "_shard" + shard_N.toString();
  }

  public static void increment(String name) {
    MemcacheService cache =
      MemcacheServiceFactory.getMemcacheService();
    Long val = cache.increment(name, 1); // atomic
    if (val == null) {
       val = Counter.read(name);
       Long init = (val == null) ? 0L : val;
       // atomic increment with initial value
       val = cache.increment(name, 1, init);
    }
    Counter.write(name, val);
  }
      </pre>
      <pre class="lesspace smallcode" style="width:400px; height:610px; font-size: 0.5em">
  // Counter.java continued

  public static Long value(String name) {
    MemcacheService cache =
      MemcacheServiceFactory.getMemcacheService();
    Long val = (Long)cache.get(name);
    if (val == null) {
      val = Counter.read(name);
      if (val != null) {
        cache.put(name, val);
      }
    }
    return val;
  }

  static Long read(String name) {
    Counter c = ofy().load().type(Counter.class)
            .filter("name", name).order("-value")
                                    .first().get();
    return (c == null ? null : c.value);
  }

  static void write(String name, Long value) {
    Random r = new Random();
    Integer shard_N = r.nextInt(10);
    ofy().save().entity(
              new Counter(name, shard_N, value));
  }
}
      </pre>
        <div class="x-small" style="margin-top:10px">usage:&nbsp;&nbsp;<span style="color: black;">Counter.increment("pluscounter"); &nbsp;&nbsp;Counter.value("minuscounter");</span></div>
    </div>

    <div class="chapter-number g-blue">10</div>
    <h3 class="num2">
        Implement a counter that scales under load
    </h3>

    <pre class="lesspace smallcode">//key = name+shard_N
public class @Entity Counter {@Id String key; @Index String name; @Index Long value;}</pre>


    <div style="margin-top:20px;">
        <div class="screenshot-left bigserif scrshottext" style="margin-right: 30px;">
            <p style="margin-top: 0px">The president is:</p>
            <div class="scrshotimg"><img src="images/candidate2_en.png"/></div>
            <div style="text-align: center;"><small>Mitt Romney</small></div>
            <table style="margin-top:10px"><tr><td class="countercell"><div class="counter">+1</div> (17K)</td><td class="countercell"><div class="counter">-1</div> (10K)</td></tr></table>
        </div>

        <p>Atomic increment in Memcache:</p>
         <pre class="lesspace smallcode">Long C = MemcacheServiceFactory
.getMemcacheService().increment("myCounter", 1);</pre>

        <p>Save the new value in one of 10 counters in the datastore:</p>
         <pre class="lesspace smallcode">
Integer shard_N = new Random().nextInt(10);
ofy().save().entity(new Counter(name,shard_N,C));</pre>
        <p>Read: if Memcache fails, MAX of the counters in the datastore:</p>
		 <pre class="lesspace smallcode">ofy().load().type(Counter.class).filter("name",
             name).order("-value").first().get();</pre>

        <translation lang="fr">
            utilisation: &nbsp;&nbsp;
            --self--
            --self--
            Implémenter un compteur qui tient la charge
            Le président est...
            Nicolas Sarkozy
            --self--
            --self--
            --self--
            --self--
            Memcache: incrément atomique 
            Sauver la nouvelle valeur dans un parmi 10 compteurs du Datastore.
            Lecture: si échec du Memcache, MAX des compteurs du datastore.
        </translation>
</article>

<!-- ------------------------------------------------------------------------------- -->
<!-- 9. Ajouter un index composite sur une entité -->

<article class="slide3d">
    <div class="backslide3d" style="padding:40px">
        <p>file: war/WEB-INF/appengine/datastore-indexes.xml</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;datastore-indexes autoGenerate="false"&gt;
     &lt;datastore-index kind="Counter" ancestor="false" source="manual"&gt;
         &lt;property name="name" direction="asc"/&gt;
         &lt;property name="value" direction="desc"/&gt;
    &lt;/datastore-index&gt;
&lt;/datastore-indexes&gt;
</pre>
        <p>The SDK generates this file automatically in <code>WEB-INF/appengine-generated/datastore-indexes-auto.xml</code> copy it to <code>WEB-INF/appengine/datastore-indexes.xml</code></p>
    </div>
    <div class="chapter-number g-green">11</div>
    <h3 class="num2">
        Add a composite index on an entity
    </h3>
    <p>&nbsp;</p>
    <ul>
        <li>The datastore can only execute indexed requests.</li>
        <li>Objectify creates an index for each property annotated with <code> @Index</code>.</li>
        <li>If you want to request on multiple properties, you have to create an index for each combination manually.</li>
        <li style="margin-top: 60px;">
        For our counter, we need a composite index on "name" and "value" DESC.</li>
    </ul>

    <translation lang="fr">
        fichier: war/WEB-INF/appengine/datastore-indexes.xml
        Le SDK autogénère ce fichier dans le le répertoire
        --self--
        à copier dans
        --self--
        --self--
        Ajouter un index multiple sur une entité
        Le datastore exécute uniquement des requêtes indexées.
        Objectify crée un index simple sur chaque propriété annotée avec
        --self--
        --self--
        Si l'on fait une requête sur plus d'une propriété, il faut créer un index pour chaque combinaison manuellement.
        Pour notre compteur, il nous faut un index combiné avec "name" et "value" DESC
    </translation>
</article>

<!-- ------------------------------------------------------------------------------- -->
<!-- 11. Blobstore and user uploads -->
     
      <article class="slide3d" > 
      <div class="backslide3d">
<p>file: war/admin.jsp</p>
<pre class="smallcode lesspace">
&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
&lt;%@page import="com.google.appengine.api.blobstore.BlobstoreServiceFactory"%&gt;

&lt;form action="&lt;%= BlobstoreServiceFactory.getBlobstoreService().createUploadUrl("/upload") %&gt;" 
	method="post" enctype="multipart/form-data"&gt;
    &lt;label&gt;<span>President's name</span> :   &lt;/label&gt; &lt;input type="text" name="president-name"/&gt;
    &lt;label&gt;<span>President's picture</span> : &lt;/label&gt; &lt;input type="file" name="president-pic"/&gt;
    &lt;input type="submit"/&gt;
&lt;/form&gt;
</pre>

file: UploadServlet.java (map it on /upload)
<pre class="smallcode lesspace">
package com.me.president;

public class UploadServlet extends HttpServlet {
  @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp)
                        throws ServletException, IOException {
    BlobstoreService bs = BlobstoreServiceFactory.getBlobstoreService();
    Map&lt;String, List&lt;BlobKey&gt;&gt; blobs = bs.getUploads(req);
    BlobKey key = blobs.get("president-pic").get(0);
    String presUrl  = ImagesServiceFactory.getImagesService().getServingUrl(key);
    String presName = req.getParameter("president-name");
    resp.sendRedirect(presUrl); // <span>just for debug</span>
    // <span>TODO: keep the name and the pic URL of the president in the datastore (using an</span>
    // <span>Objectify class) and use these values to display the elected president.</span>
  }
}
</pre>

      </div>
        <div class="chapter-number g-blue">12</div>
        <h3 class="num2">
          Upload the photo of the president using Blobstore and ImageService.
        </h3>
        <!-- 
        <div class="screenshot-left" style="margin-right: 25px;">
        	<img  src="images/scrshot_formulaire_envoie.png" width="300px"/>
        </div>
         -->
        <p>Create a form for uploading a photo to a URL given by the Blobstore:</p>
        <pre class="smallcode lesspace">
&lt;% url = BlobstoreServiceFactory.getBlobstoreService().createUploadUrl("/upload"); %&gt;
&lt;form action="&lt;%= url %&gt;" method="post" enctype="multipart/form-data"&gt;
&lt;input type="file" name="president-pic"/&gt; ...</pre>
        <p>Get the Blobstore key of the picture in the servlet
 <code>/upload</code>:</p>
        <pre class="lesspace">
void doPost(HttpServletRequest req, HttpServletResponse resp) {
BlobstoreService bs = BlobstoreServiceFactory.getBlobstoreService();
BlobKey key = bs.getUploads(req).get("president-pic").get(0); ...</pre>
        <p>Serve it to the client using the ImageService:</p>
        <pre class="lesspace">ImagesServiceFactory.getImagesService().getServingUrl(key);</pre>

        <translation lang="fr">
        fichier: war/admin.jsp
Nom du président
Photo du président
        fichier: UploadServlet.java (servlet à mapper sur /upload)
juste pour débugger
A FAIRE: conserver le nom et l'URL de l'image du président dans le datastore
(une classe Objectify) et utiliser ces valeurs pour afficher le président à l'heure H.
		--self--
		Uploader la photo du président grâce à Blobstore et ImageService
		Créer un formulaire d'upload vers une URL donnée par le Blobstore:
		Récupérer la clé de l'image dans la servlet&nbsp;
    --self--
    :
				La servir au client grâce à ImageService:
        </translation>
      </article>

<!-- ------------------------------------------------------------------------------- -->
<!-- 12. Security Constraint Administration -->

      	  <article class="slide3d" > 
      <div class="backslide3d">
<p>file: war/WEB-INF/web.xml</p>
<pre class="smallcode lesspace">
&lt;security-constraint&gt;
    &lt;web-resource-collection&gt;
        &lt;url-pattern&gt;/cron*&lt;/url-pattern&gt;
        &lt;url-pattern&gt;/admin.jsp&lt;/url-pattern&gt;
        &lt;url-pattern&gt;/upload&lt;/url-pattern&gt;
    &lt;/web-resource-collection&gt;
    &lt;auth-constraint&gt;
        &lt;role-name&gt;admin&lt;/role-name&gt;
    &lt;/auth-constraint&gt;
&lt;/security-constraint&gt;
</pre>
      </div>
        <div class="chapter-number g-red">13</div>
        <h3 class="num2">
          Secure admin URLs
        </h3>
        <p>&nbsp;</p>
        <ul>
        <li>You can set security constraints in the web.xml file.</li>
        <li>The restricted access role is: <strong>admin</strong></li>
        <li>User authentication is performed automatically.</li>
        <li>CRON jobs are launched in admin mode.</li>
        </ul>
        
        <translation lang="fr">
        fichier: war/WEB-INF/web.xml
        --self--
        Protéger les URLs accessibles par les administrateurs
        Il suffit d'ajouter une contrainte de sécurité dans le fichier web.xml
        Indiquez le role :
        admin
        La vérification est faite automatiquement
        Les tâches planifiées sont lancées par Google App Engine en mode administrateur.
        </translation>
        
      </article>
      
<!-- ------------------------------------------------------------------------------- -->
<!-- 13. Receiving emails -->

      	  <article class="slide3d" > 
      <div class="backslide3d">
<p><span>file:</span> src/com/me/president/MailHandler.java</p>
<pre class="smallcode lesspace">
package com.me.president;
import java.util.Properties;
import javax.mail.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MailHandlerServlet extends HttpServlet { 
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws Exception { 
        Properties props = new Properties(); 
        Session session = Session.getDefaultInstance(props, null); 
        MimeMessage message = new MimeMessage(session, req.getInputStream());
        Comment.store((String)((Multipart)message.getContent()).getBodyPart(0).getContent()
            , ((InternetAddress)message.getFrom()[0]).getAddress());
        Message reply = message.reply(false);
        reply.setFrom(new InternetAddress("noreply@cloudpresident.appspotmail.com"));
        reply.setText("<span>Thank you for your opinion.</span>");
        Transport.send(reply);
    }
}
</pre>
      </div>
        <div class="chapter-number g-yellow">14</div>
        <h3 class="num2">
          Post comments by email
        </h3>
        <p>&nbsp;</p>
        <div>
        <p>Enable email reception on address <span class="u"><span>name</span>@id_application.appspotmail.com</span></p>
<pre class="smallcode lesspace">&lt;inbound-services&gt;
      &lt;service&gt;mail&lt;/service&gt;
&lt;/inbound-services&gt;</pre>
        <p>Create a servlet mapped on &nbsp;&nbsp; /_ah/mail/*</p>
        <p>To read the contents of an email:</p>
<pre class="smallcode lesspace">Properties props = new Properties(); 
Session session = Session.getDefaultInstance(props, null); 
MimeMessage message = new MimeMessage(session, req.getInputStream());</pre>
        </div>
        
        <translation lang="fr">
        fichier:
        --self--
Merci pour votre commentaire
        --self--
        Recevoir un mail
        Indiquez que l'application peut recevoir des mails sur 
        nom
        --self--
        Créer une servlet mappé sur l'URL /_ah/mail/*
        Lire le contenu du mail : 
        </translation>
        
      </article>
      
<!-- ------------------------------------------------------------------------------- -->
<!-- slide finale: contact info -->
      <article class="slide3d">
      <div class="empty backslide3d"></div>
        
        <p style="margin-left: 3em; margin-top: 1em; text-indent: -2em; background-image: url('images/appengine_small.png'); background-repeat: no-repeat; background-position: 100% 0%">
        Contact : <br/>
          <b>+Alexis Moussine-Pouchkine</b>, Google<br/>
          <b>+Martin Görner</b>, Google,
          <a href="http://gplus.to/martin.gorner">gplus.to/martin.gorner</a><br/>
          <b>+Didier Girard</b>, SFEIR<br/>

        </p>
        <p style="margin-left: 3em; margin-top: 3.0em; text-indent: -2em;">This presentation is available online:<br/>
        <a href="http://cloudpresident.appspot.com">http://<b><span class="big">cloudpresident</span></b>.appspot.com</a><br/>
        <p style="margin-left: 3em; margin-top: 3.0em; text-indent: -2em;">More info<br/>
        <a href="http://developers.google.com/appengine/">http://developers.google.com/appengine</a>
        </p>
        
        <translation lang="fr">
            --self--
            --self--
            --self--
            --self--
            --self--
            --self--
            --self--
            --self--
            Cette présentation est en ligne :
            --self--
            --self--
            --self--
            Plus d'infos :
            --self--
        </translation>
      </article>

    </section>


  </body>
</html>
